/*
 * Copyright (C) <2009> 
 *
 * <Rishi B Agrawal> <Sneha Hendre>
 * <rishi.b.agrawal@gmail.com> <sneha.hendre@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License as published by the 
 * Free Software Foundation, either version 3 of the License, or (at your 
 * option) any later version->
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE->  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include "../include/ohsm.h"
#include "ohsm_u.h"


unsigned char flg_i_usr = UNSET,flg_usr = UNSET;
unsigned char flg_i_grp = UNSET,flg_grp = UNSET;
unsigned char flg_i_types = UNSET,flg_types = UNSET;

int 
parseinfo (xmlDocPtr doc, xmlNodePtr cur, unsigned int *users, unsigned int *groups, unsigned int *types) {

	xmlChar *key;
	int temp;
	int no;
	
	cur = cur->xmlChildrenNode;
	cur = cur->next;
	
	while( cur != NULL) {
		
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "NR_USERS"))) {
			flg_i_usr = SET;
			key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
			temp = validate_key (key);
			
			if (temp == -1) {
				no = (int)xmlGetLineNo (cur);
				printf("\nOHSM: [%d] : wrong value in <info><users> tag", no);
				printf("\nOHSM: [%d] : fatal : cannot proceed further", no);
				return -1;
			} else {
				*users = temp;
			}
			
			#ifdef ALL_DEBUG
			printf ("\nOHSM: The Number of users : %u", *users);
			#endif
			xmlFree (key);
		}
		cur = cur->next->next;
		
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "NR_GROUPS"))) {
			flg_i_grp = SET;
			key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
			temp = validate_key (key);
			
			if (temp == -1) {
				no = ( int )xmlGetLineNo (cur);
				printf("\nOHSM: [%d] : wrong value in <info><groups> tag", no);
				printf("\nOHSM: [%d] : fatal : cannot proceed further", no);
				return -1;
			} else {
				*groups = temp;
			}
			
			#ifdef ALL_DEBUG
			printf ("\nOHSM: Number of Groups = %u\n", *groups);
			#endif
			xmlFree (key);
		}
		cur = cur->next->next;
		
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "NR_TYPES"))) {
			flg_i_types = SET;
			key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
			temp = validate_key (key);
			
			if (temp == -1) {
				no = ( int )xmlGetLineNo (cur);
				printf("\nOHSM: [%d] : wrong value in <info><types> tag", no);
				printf("\nOHSM: [%d] : fatal : cannot proceed further", no);
				return -1;
			} else {
				*types = temp;
			}
			
			#ifdef ALL_DEBUG
			printf ("\nOHSM: Number of Types = %u\n", *types);
			#endif
			xmlFree (key);
		}
		cur = cur->next->next;
	}

	if (flg_i_usr == UNSET) { *users = 0; }
	if (flg_i_grp == UNSET) { *groups = 0; }
	if (flg_i_types == UNSET) { *types = 0; }
	
	return 0;
}


int 
parseuser (xmlDocPtr doc, xmlNodePtr cur, const unsigned int number) {
	
	xmlChar *key;

	int temp, no;
	int cnt_users = 0, retval;
	cur = cur->xmlChildrenNode;
	cur = cur->next;
	while (cur != NULL){
		
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "USER"))){
			flg_usr = SET;
			cnt_users++;
			
			if( cnt_users > number) {
				no = (int) xmlGetLineNo (cur);
				printf("\nOHSM: error number of users in <info><users> is less than the entered users");
				return -1;
			} else {
				key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
				temp = validate_key (key);
				
				if( temp == -1){
					no = (int) xmlGetLineNo (cur);
					printf("\nOHSM: [%d] : wrong value in <user> tag", no);
					printf("\nOHSM: [%d] : fatal : cannot proceed further", no);
					return -1;
				} 

				retval = validate_user (temp);

				if ( retval ) {
					allocpol->uid_tier[allocpol->uidx].uid = temp;
				} else {
					no = (int) xmlGetLineNo (cur);
					printf("\nOHSM: [%d] : wrong value in <user> tag", no);
					printf("\nOHSM: [%d] : user does not exists", temp);
				}
				xmlFree (key);
			}
		}
		cur = cur->next;
	
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "TIER"))){
			key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
			temp = validate_key (key);
			
			if( temp == -1 ){
				printf("\nOHSM: Invalid tier entered");
				return -1;				
			}
			allocpol->uid_tier[allocpol->uidx++].tier = temp; 	
			xmlFree (key);
		}
		cur = cur->next->next;
	}

	if (cnt_users < number) {
		no = (int) xmlGetLineNo (cur);
		printf("\nOHSM: Number of users in <info> greater than users specified");
		return -1;
	}
	return 0;			//sucessful
}

int 
parsegroup (xmlDocPtr doc, xmlNodePtr cur, unsigned int groups) {

	xmlChar *key;
	unsigned int temp_gid;
	unsigned int cnt_groups = 0 ;
	int retval, temp, no;

	cur = cur->xmlChildrenNode;
	cur = cur->next;
	while (cur != NULL) {

		if ((!xmlStrcmp (cur->name, (const xmlChar *) "GROUP"))){
			flg_grp = SET;
			cnt_groups++;
			
			if (cnt_groups >  groups) {
				no = (int) xmlGetLineNo (cur);
				printf("\nOHSM: error number of groups in <info><groups> is less than the entered groups");
				return -1;

			} else {
					
				key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
				temp = validate_key (key);
				
				if (temp == -1) {
					no = (int) xmlGetLineNo (cur);
					printf("\nOHSM: [%d] : wrong value in <group> tag", no);
					printf("\nOHSM: [%d] : fatal : cannot proceed further", no);
					return  temp;
				}
				retval = validate_group (temp);
				if (retval > 0) {
						allocpol->gid_tier[allocpol->gidx].gid = temp; 	
				} else {
					no = (int) xmlGetLineNo (cur);
					printf("\nOHSM: [%d] : error %u gid not present on system", no, temp);
				}
				xmlFree (key);
			}
		}
		cur = cur->next;
		
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "TIER"))){
			key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
			temp = validate_key (key);
			
			if (temp == -1) {
				no = (int) xmlGetLineNo (cur);
				printf("\nOHSM: [%d] : wrong value in <group> tag", no);
				printf("\nOHSM: [%d]: fatal : cannot proceed further", no);
				return temp;
			}				
			allocpol->gid_tier[allocpol->gidx++].tier = temp; 	
			xmlFree (key);
		}
		cur = cur->next->next;
	}
	if (cnt_groups < groups) {
	 	no = (int) xmlGetLineNo (cur);
		printf("\nOHSM: %u %u: error number of groups in <info> greater than groups spcified", cnt_groups, groups);
	}
	return 0;			//successful
}

int 
parsetypes (xmlDocPtr doc, xmlNodePtr cur, unsigned int types) {

	xmlChar *key;
	unsigned int cnt_types = 0;
	char *temp_name = NULL;
	int temp,no;
		
	cur = cur->xmlChildrenNode;
	cur = cur->next;
	while (cur != NULL) {
		
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "TYPE"))){
			flg_types = SET;
			cnt_types++;
		
			if (cnt_types > types) {
				no = (int) xmlGetLineNo (cur);
				printf("\nOHSM:  %u %u : error number of types in <info><types> is less than the entered types", cnt_types, types);
				break;
			
			} else {
				key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
				temp_name = (char *) key;
				strcpy(allocpol->type_tier[allocpol->tidx].type, temp_name); 	
				xmlFree (key);
			}
		}
		cur = cur->next->next;
		
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "TIER"))){
			
			key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
			temp = validate_key (key);
			
			if (temp == -1) {
				no = (int) xmlGetLineNo (cur);
				printf("\nOHSM: [%d] : wrong value in <tier> tag", no);
				printf("\nOHSM: [%d]: fatal : cannot proceed further", no);
				return temp;				
			} else {
				allocpol->type_tier[allocpol->tidx++].tier = temp; 	
				xmlFree (key);
			}
		}
		cur = cur->next->next;
	}
	
	if (cnt_types < types) {
		no = (int) xmlGetLineNo (cur);
		printf("\nOHSM: %u %u: error number of types in <info> greater than types spcified", cnt_types, types);
		return -1;
	}
	return 0;			
}

int 
parsedoc (char *docname) {

	xmlDocPtr doc;
	xmlNodePtr cur;
	unsigned int users, groups, types;
	int retval;
	
	xmlLineNumbersDefault (1);
	doc = xmlParseFile (docname);
	if (!doc) {
		printf ("\nOHSM: Document not parsed successfully");
		xmlFreeDoc (doc);
		return -1;
	}
	
	cur = xmlDocGetRootElement (doc);
	if (cur == NULL){
		printf ("\nOHSM: empty document");
		xmlFreeDoc (doc);
		return -1;
	}

	if (xmlStrcmp (cur->name, (const xmlChar *) "CREATE")){
		printf ("\nOHSM: Invalid document Root element not equal to create...");
		xmlFreeDoc (doc);
		return -1;
	}

	cur = cur->xmlChildrenNode;
	cur = cur->next;
	while (cur != NULL) {
		
		if ((!xmlStrcmp (cur->name, (xmlChar *) "INFO"))){
			
			retval = parseinfo (doc, cur, &users, &groups, &types);
			if(retval)
				return retval;
			
			allocpol->cnt_users = users;
			allocpol->cnt_groups = groups;
			allocpol->cnt_types = types;
		}
		cur = cur->next->next;
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "USERS"))){
						
			if (users) {
				retval = parseuser (doc, cur, users);
				if (retval) {
					return retval;
				}
			}
		}
		cur = cur->next->next;
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "GROUPS"))){
			 
			if (groups) {
				retval = parsegroup (doc, cur, groups);
				if (retval) {
					return retval;
				}
			}
		}
		cur = cur->next->next;
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "TYPES"))){
			
			if (types) {				
				retval = parsetypes (doc, cur, types);
				if (retval) {
					return retval;
				}
			}
		}
		cur = cur->next->next;
	}
	xmlFreeDoc (doc);
	return 0;
}


int
ohsm_get_allocation_policy (char *filename) {

	int retval;
	char cmd[80];
	
	sprintf(cmd,"xmllint --valid --noout %s",filename);	
	retval = system(cmd);
	if (!retval) {
		retval = parsedoc (filename);
		if (retval) {
			return -1;
		}
	} 

	if (retval) {
		if (flg_grp ^ flg_i_grp) {
			printf("\nOHSM: [%s] : error GRP and <groups> tag mismatch ",filename);
		}
		
		if (flg_usr ^ flg_i_usr) { 
			printf("\nOHSM [%s] : error USER and <users> tag mismatch ",filename);
		}
		
		if (flg_types ^ flg_i_types) { 
			printf("\nOHSM [%s] : error TYPE and <types> tag mismatch ",filename);
		}
	}
	return retval;
}
